package com.lz.helper.camera;

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Choreographer;
import android.view.TextureView;

import java.util.List;

import siren.ocean.yuv.YuvUtil;


public class CameraView extends TextureView {

    private final static String TAG = "CameraView";
    private Camera mCamera;
    private CameraParameter mParameter;

    public CameraView(Context context) {
        this(context, null, 0);
    }

    public CameraView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void openCamera() {
        try {
            if (isAvailable()) {
                Log.d(TAG, "openCamera: ");
                releaseCamera();
                mCamera = Camera.open(mParameter.getCameraId());
                mCamera.setPreviewTexture(getSurfaceTexture());
                initParameter();
            }
        } catch (Exception e) {
            e.printStackTrace();
            Choreographer.getInstance().postFrameCallbackDelayed(frameTimeNanos -> {
                Log.d(TAG, "reconnect: ");
                openCamera();
            }, 2000);
        }
    }

    /**
     * 设置自动对焦模式
     */
    private void initFocusModes() {
        try {
            Parameters parameters = mCamera.getParameters();
            List<String> supportedFocusModes = parameters.getSupportedFocusModes();
            if (supportedFocusModes != null && supportedFocusModes.contains(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
                parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
            }
            if (supportedFocusModes != null && supportedFocusModes.contains(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            }
            mCamera.setParameters(parameters);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initParameter() {
        initFocusModes();
        initDisplayOrientation();
        initPreviewSize();
        initPreviewBuffer();
        mCamera.startPreview();
        requestLayout();
    }

    /**
     * 初始化预览尺寸大小
     */
    private void initPreviewSize() {
        Parameters parameters = mCamera.getParameters();
        Log.d("initPreviewSize: ", mParameter.getResolution()[0] + ":::" + mParameter.getResolution()[1]);
        parameters.setPreviewSize(mParameter.getResolution()[0], mParameter.getResolution()[1]); // 设置预览分辨率
        mCamera.setParameters(parameters);
    }

    /**
     * 设置相机显示的方向
     */
    private void initDisplayOrientation() {
        mCamera.setDisplayOrientation(mParameter.getOrientation());
    }

    /**
     * 释放相机资源
     */
    public void releaseCamera() {
        if (null != mCamera) {
            mCamera.setPreviewCallbackWithBuffer(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int originalWidth = MeasureSpec.getSize(widthMeasureSpec);
        int originalHeight = MeasureSpec.getSize(heightMeasureSpec);
        Log.d("lzkeji", originalWidth + "  measure " + originalHeight);
        int finalWidth, finalHeight;
        float scale = (float) mParameter.getResolution()[1] / (float) mParameter.getResolution()[0];
        if (originalWidth < originalHeight) {
            finalWidth = originalWidth;
            finalHeight = (int) (finalWidth / scale);
        } else {
            finalWidth = originalWidth;
            finalHeight = (int) (finalWidth * scale);
        }
        Log.d("lzkeji", finalWidth + " final " + finalHeight);
//        setMeasuredDimension(finalWidth, finalHeight);


        super.onMeasure(MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY));
    }

    private Camera.PreviewCallback mPreviewCallback;
    public byte[] mPreviewBuffer;

    private void initPreviewBuffer() {
        mPreviewBuffer = new byte[mParameter.getResolution()[0] * mParameter.getResolution()[1] * 3 / 2]; // 初始化预览缓冲数据的大小
        mCamera.addCallbackBuffer(mPreviewBuffer); // 将此预览缓冲数据添加到相机预览缓冲数据队列里
        mCamera.setPreviewCallbackWithBuffer(mPreviewCallback); // 设置预览的回调
    }

    public interface PreviewCallback {
        void onPreviewFrame(byte[] data, int width, int height);
    }

    public void setPreviewCallback(PreviewCallback callback) {
        mPreviewCallback = (data, camera) -> {
            addCallbackBuffer();
            byte[] imageData = YuvUtil.nv21RotateMirror(data, mParameter.getResolution()[0], mParameter.getResolution()[1], mParameter.getRotation(), mParameter.isMirror(), 1);
            int w, h;
            //如果流数据做了直角旋转，则必然导致宽高互换
            if (mParameter.getRotation() == 90 || mParameter.getRotation() == 270) {
                w = mParameter.getResolution()[1];
                h = mParameter.getResolution()[0];
            } else {
                w = mParameter.getResolution()[0];
                h = mParameter.getResolution()[1];
            }
            callback.onPreviewFrame(imageData, w, h);
        };
    }

    /**
     * 每次预览的回调中，需要调用这个方法才可以起到重用mBuffer
     */
    public void addCallbackBuffer() {
        if (mCamera != null) {
            mCamera.addCallbackBuffer(mPreviewBuffer);
        }
    }

    public void setParameter(CameraParameter parameter) {
        this.mParameter = parameter;
//        openCamera();
    }
}